﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Configuration.Install;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.ServiceProcess;
using Autofac;
using uTILLIty.Rave.Core;
using uTILLIty.Rave.Service.Properties;

namespace uTILLIty.Rave.Service
{
	static class Program
	{
		private static IContainer _container;

		internal static IContainer Container
		{
			get { return _container ?? (_container = CreateContainer()); }
		}

		private static IContainer CreateContainer()
		{
			var builder = new ContainerBuilder();
			builder.RegisterModule<IocModule>();
			builder.RegisterType<DirCreatorService>();
			IContainer container = builder.Build();
			return container;
		}

		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		static void Main(string[] args)
		{
			EnsureCurrentDirectory(); //on service-run it's c:\windows\system32
      if (FindArgument(args, "/?") || FindArgument(args, "-?"))
      {
        PrintHeader();
        Console.WriteLine(Resources.CommandlineParameters);
        return;
      }
      if (FindArgument(args, "--install") || FindArgument(args, "-i"))
      {
        PrintHeader();
        Install(false, args);
        return;
      }
      if (FindArgument(args, "--uninstall") || FindArgument(args, "-u"))
			{
        PrintHeader();
        Install(true, args);
				return;
			}

			if (FindArgument(args, "--console") || FindArgument(args, "-c"))
			{
        PrintHeader();
        var service = Container.Resolve<DirCreatorService>();
				AddConsoleTraceListener(service);
				RunInConsoleMode(service);
				return;
			}
			if (args == null || args.Length == 0)
			{
				var service = Container.Resolve<DirCreatorService>();
				var services = new ServiceBase[] { service };
        try
        {
          ServiceBase.Run(services);
        }
        catch (Exception ex)
        {
          PrintHeader();
          Console.WriteLine(ex.Message);
          Console.WriteLine(Resources.CommandlineParameters);
        }
			  return;
			}
      PrintHeader();
      Console.WriteLine(Resources.CommandlineParameters);
		}

	  private static void PrintHeader()
	  {
      FileVersionInfo fileInfo = FileVersionInfo.GetVersionInfo(typeof(Program).Assembly.Location);
      FileVersionInfo coreFileInfo = FileVersionInfo.GetVersionInfo(typeof(IocModule).Assembly.Location);
      // ReSharper disable LocalizableElement
      Console.WriteLine("{0} V. {1}", fileInfo.ProductName, coreFileInfo.ProductVersion);
      // ReSharper restore LocalizableElement
    }

	  private static void EnsureCurrentDirectory()
		{
			var exeDir = Path.GetDirectoryName(typeof(Program).Assembly.Location);
			// ReSharper disable PossibleNullReferenceException
			if (!exeDir.Equals(Directory.GetCurrentDirectory()))
				Directory.SetCurrentDirectory(exeDir);
			// ReSharper restore PossibleNullReferenceException
		}

		private static void AddConsoleTraceListener(DirCreatorService service)
		{
			service.TraceSource.Listeners.Add(new ConsoleTraceListener());
		}

		private static void RunInConsoleMode(DirCreatorService service)
		{
			Console.WriteLine(Resources.ConsoleModeStartingService);
			service.StartService();
			Console.WriteLine(Resources.ConsoleModeServiceStarted);
			while (true)
			{
				var key = Console.ReadKey(true);
				if (key.Key == ConsoleKey.Enter)
					break;
			}
			service.Stop();
			Console.WriteLine(Resources.ConsoleModeStoppedService);
		}

		private static void Install(bool uninstall, string[] args)
		{
			try
			{
				Console.WriteLine(uninstall ? Resources.UninstallingService : Resources.InstallingService);
				using (var inst = new AssemblyInstaller(typeof(Program).Assembly, args))
				{
					IDictionary state = new Hashtable();
					inst.UseNewContext = true;
					try
					{
						if (uninstall)
						{
							inst.Uninstall(state);
						}
						else
						{
							inst.Install(state);
							inst.Commit(state);
						}
					}
					catch
					{
						try
						{
							inst.Rollback(state);
						}
						catch (Exception ex)
						{
							Console.WriteLine(Resources.ErrorOnRollback, ex.Message);
						}
						throw;
					}
				}
			}
			catch (Exception ex)
			{
				Console.WriteLine(ex.Message);
			}
		}

		private static bool FindArgument(IEnumerable<string> args, string arg)
		{
			return args != null && args.Any(a => arg.Equals(a, StringComparison.CurrentCultureIgnoreCase));
		}
	}
}
